#--------------------------------------------------------------------------
# 本程序用来计算2024版《湖北师范大学课程目标达成情况评价分析报告》中的课程目标达成度
#（表四——课程目标达成度计算结果）
# 使用说明：请按示例excel文件样式准备输入数据，文件中共需准备5张表
#--------------------------------------------------------------------------
import pandas as pd
import numpy as np

# 程序中出现的变量说明：
# scores              : 学生成绩单 (各考核项单列)
# scores_final        : 学生成绩单（总评成绩）
# scores_fenti        : 学生期末考试成绩（各考题单列，不列总成绩）
# scores_fenmubiao    : 学生成绩单（各分目标分数单列）
# weights             : 各考核项权重
# KHfangshi           : 考核方式名称
# num_stdn            : 学生人数  
# num_kaohe           : 考核项个数
# num_mubiao          : 课程目标个数
# num_ti              : 期末考试考题个数
# mubiao_fenti        : 期末考试分数分目标分布（表二——支撑课程目标的期末考核分数分布）
# fenjie              : 各考核方式对分目标的支撑（表三——支撑课程目标的各考核环节...）
# avg_sc_fenxiang     : 各考核项的全班平均分
# avg_sc_fenmubiao    : 各考核项的分目标全班平均分
# dachengdu_fenmubiao : 各考核项的分目标全班达成度
# dachengdu_final     : 课程全班总达成度

#--- 读入学生成绩单 ---
# 注：成绩单需按照考核项（笔试、作业、出勤等）单列，表格前三列需为序号、学号、姓名
scores = pd.read_excel('达成度计算输入表.xlsx', sheet_name='考核项得分',header=0)
num_stdn = scores.shape[0]
num_kaohe = scores.shape[1]-3

#--- 读入各考核项权重 ---
# 注：weights 给出每项考核的权总，个数=num_kaohe，顺序与成绩排列相同，总和为1
weights = pd.read_excel('达成度计算输入表.xlsx', sheet_name='权重',header=0).values

#--- 计算每位学生的总评成绩 ---
KHfangshi = scores.columns[3:]
scores_final = pd.Series(np.zeros(num_stdn))
for i in range(num_kaohe):
    #print(scores[KHfangshi[i]], weights[0][i])
    scores_final += scores[KHfangshi[i]] * weights[0][i]
# 教务处规定考试成绩低于50分的不给及格，最终得分等于考试成绩
scores_kaoshi = scores[KHfangshi[0]]
scores_final[scores_kaoshi<50] = scores_kaoshi[scores_kaoshi<50]
# 四舍五入
scores_final=np.round(scores_final)

#--- 计算总评成绩的最高、最低、平均分 ---
print(scores_final)
max_sc = np.max(scores_final)
min_sc = np.min(scores_final)
avg_sc = np.round(np.mean(scores_final))

#--- 计算分项成绩的平均分 ---
avg_sc_fenxiang = np.array([])
for i in range(num_kaohe):
    avg_sc_fenxiang = np.append(avg_sc_fenxiang, np.mean(scores[KHfangshi[i]]))

#--- 计算考试分目标得分 ---
scores_fenti = pd.read_excel('达成度计算输入表.xlsx', sheet_name='考试分题得分',header=0)
mubiao_fenti = pd.read_excel('达成度计算输入表.xlsx', sheet_name='考试目标分数构成',header=0)
num_mubiao = mubiao_fenti.shape[0]
num_ti = mubiao_fenti.shape[1]-2
scores_fenmubiao = np.zeros((num_stdn, num_mubiao))
for i in range(num_stdn):
    for j in range(num_mubiao):
        for k in range(num_ti):
            scores_fenmubiao[i,j]+=scores_fenti.iloc[i,k+3]*mubiao_fenti.iloc[j,k+1]/np.sum(mubiao_fenti.iloc[:,k+1])

#--- 计算各分数段学生人数和比例 ---
num_YX = np.count_nonzero(scores_final>=90)
num_LH = np.count_nonzero((80<=scores_final) & (scores_final<90) )
num_ZD = np.count_nonzero((70<=scores_final) & (scores_final<80) )
num_JG = np.count_nonzero((60<=scores_final) & (scores_final<70) )
num_BJG = np.count_nonzero(scores_final<60)
if (num_YX + num_LH + num_ZD + num_JG + num_BJG != num_stdn):
    print('各分数段人数总和不等于总人数，请检查计算过程！') 
perc_YX = num_YX/num_stdn * 100.
perc_LH = num_LH/num_stdn * 100. 
perc_ZD = num_ZD/num_stdn * 100. 
perc_JG = num_JG/num_stdn * 100. 
perc_BJG = num_BJG/num_stdn * 100. 

#--- 读入分目标评价方法，准备计算分目标达成度 ---
fenjie = pd.read_excel('达成度计算输入表.xlsx', sheet_name='目标分解',header=0)
num_mubiao = fenjie.shape[0]
avg_sc_fenmubiao = np.zeros((num_mubiao, num_kaohe))

#--- 计算分目标平均分 ---
for i in range(0,num_mubiao):
    avg_sc_fenmubiao[i,0] = np.mean(scores_fenmubiao[:,i])
    avg_sc_fenmubiao[i,1:] = avg_sc_fenxiang[1:] * fenjie.iloc[i,2:]/100. 

#--- 计算分目标达成度 ---
dachengdu_fenmubiao = np.zeros((num_mubiao))
for i in range(num_mubiao):
    weights_sum = 0.
    for j in range(num_kaohe):
        if fenjie.iloc[i,j+1] > 0:
            dachengdu_fenmubiao[i] += avg_sc_fenmubiao[i,j]/fenjie.iloc[i,j+1]*weights[0][j]
            weights_sum += weights[0][j]
    dachengdu_fenmubiao[i] = dachengdu_fenmubiao[i]/weights_sum
#--- 计算总达成度 ---
dachengdu_final = np.mean(dachengdu_fenmubiao)

#--- 计算结束，输出达成度评价报告中需要填的数值（表四）---
print('最高分：', max_sc,'最低分：',min_sc,'平均分：',avg_sc)
print('优秀人数及比例：',num_YX,',', str(round(perc_YX,2))+'%')
print('良好人数及比例：',num_LH,',', str(round(perc_LH,2))+'%')
print('中等人数及比例：',num_ZD,',', str(round(perc_ZD,2))+'%')
print('及格人数及比例：',num_JG,',', str(round(perc_JG,2))+'%')
print('不及格人数及比例：',num_BJG,',', str(round(perc_BJG,2))+'%')
for i in range(num_mubiao):
    mb_str = '目标'+str(i+1)
    print(mb_str+'各考核项满分：', fenjie.loc[i].tolist()[1:])
    print(mb_str+'各考核项平均分：', np.round(avg_sc_fenmubiao[i,:],2))
    print(mb_str+'达成度：', np.round(dachengdu_fenmubiao[i],3))
print('总达成度：', np.round(dachengdu_final,3))
